package cn.stimd.spring.jdbc.core;

import cn.stimd.spring.dao.DataAccessException;
import cn.stimd.spring.jdbc.datasource.DataSourceUtils;
import org.springframework.util.CollectionUtils;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;

/**
 * Created by Stimd
 * 项目地址：https://gitee.com/stimd/spring-wheel
 * 公众号：Java编程探微
 */
public class JdbcTemplate implements JdbcOperations{
    private DataSource dataSource;

    public JdbcTemplate(DataSource dataSource) {
        this.dataSource = dataSource;
    }


    @Override
    public <T> List<T> query(String sql, RowMapper<T> rowMapper, Object... args) {
        List<T> list = new ArrayList<>();
        Connection connection = null;
        PreparedStatement statement = null;
        ResultSet rs = null;

        try {
            //1. 获取数据库连接和预处理语句
            connection = DataSourceUtils.getConnection(this.dataSource);
            statement = connection.prepareStatement(sql);

            //2. 填充查询参数
            for (int i = 0; i < args.length; i++) {
                statement.setObject(i +1, args[i]);
            }

            //3. 执行查询
            rs = statement.executeQuery();

            //4. 对查询结果进行处理
            int n = 1;
            while(rs.next()){
                list.add(rowMapper.mapRow(rs, n++));
            }
        } catch (Exception e) {
            release(rs, statement, connection);
            throw new RuntimeException(e);
        } finally {
            release(rs, statement, connection);
        }
        return list;
    }


    @Override
    public <T> T queryForObject(String sql, RowMapper<T> rowMapper, Object... args) {
        List<T> results = query(sql, rowMapper, args);

        if (CollectionUtils.isEmpty(results)) {
            throw new DataAccessException("查询单条数据，结果集为空");
        }

        if (results.size() > 1) {
            throw new DataAccessException("期望的查询结果数量为1，实际为" + results.size());
        }
        return results.iterator().next();
    }


    @Override
    public int update(String sql, Object... args) {
        Connection connection = null;
        PreparedStatement statement = null;
        try {
            connection = DataSourceUtils.getConnection(this.dataSource);
            statement = connection.prepareStatement(sql);
            for (int i = 0; i < args.length; i++) {
                statement.setObject(i + 1, args[i]);
            }
            return statement.executeUpdate();
        } catch (Exception e) {
            release(null, statement, connection);
            throw new RuntimeException(e);
        } finally{
            release(null, statement, connection);
        }
    }


    //释放资源
    private void release(ResultSet rs, Statement statement, Connection con) {
        if(rs != null)
            try{
                rs.close();
            }catch (Exception e) {e.printStackTrace();}

        if(statement != null)
            try{
                statement.close();
            }catch (Exception e) {e.printStackTrace();}

        if(con != null) {
            DataSourceUtils.releaseConnection(con, this.dataSource);
        }
    }
}
